﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;
using ClientOverflow.DataTransferObjects;
using ClientOverflow.ViewModels.Interfaces;
using DynamicControllersGeneration;
using System.Linq;

namespace ClientOverflow.ViewModels.PostQuestion
{
    /// <summary>
    /// PostQuestionViewModel is a view-model over Question class. The view-model is a base for Dynamic Proxy which
    /// implements the routing to the model and the implementation of errors validation. The post question exposes
    /// properties for filling the answer and commands for adding tags and posting the question.
    /// This class cannot be instantiated directly, new instances can be created using the factory method
    /// CreatePostQuestionViewModel which calls the view models generator.
    /// </summary>
    public abstract class PostQuestionViewModel : IDataErrorInfo, IPostQuestionViewModel
    {
        public static PostQuestionViewModel CreatePostQuestionViewModel(Question question)
        {
            return viewModelGenerator.Generate<PostQuestionViewModel>(question);
        }

        private const string MANDATORY_FIELD_ERROR_MESSAGE = "This field is mandatory";
        private const string TAGS_ARE_MANDATORY_ERROR_MESSAGE = "At least one tag is required";
        private const string TITLE_COLUMN_NAME = "Title";
        private const string CONTENT_COLUMN_NAME = "Content";
        private const string TAGS_COLUMN_NAME = "Tags";

        private readonly Question question;
        private readonly Dictionary<string, string> errors = new Dictionary<string, string>();
        private string[] allTags;
        private static readonly ViewModelGenerator viewModelGenerator = new ViewModelGenerator();

        protected PostQuestionViewModel(Question question)
        {
            this.question = question;
            Save = new SaveQuestionCommand(question);
            for (int i = question.Tags.Count; i < 5; i++)
            {
                question.Tags.Add(new Tag());
            }

            UpdateTitleError();
            UpdateContentError();
            UpdateTagsError();
        }

        private void UpdateTagsError()
        {
            if(question.Tags.Count == 0)
            {
                errors[TAGS_COLUMN_NAME] = TAGS_ARE_MANDATORY_ERROR_MESSAGE;
            }
            else
            {
                errors[TAGS_COLUMN_NAME] = null;
            }
        }

        private void UpdateTitleError()
        {
            errors[TITLE_COLUMN_NAME] = CheckForMandatoryError(question.Title);
        }

        private void UpdateContentError()
        {
            errors[CONTENT_COLUMN_NAME] = CheckForMandatoryError(question.Content);
        }

        private static string CheckForMandatoryError(string value)
        {
            return string.IsNullOrEmpty(value) ? MANDATORY_FIELD_ERROR_MESSAGE : null;
        }

        public string this[string columnName]
        {
            get { return errors[columnName]; }
        }

        public string Error
        {
            get { throw new NotImplementedException(); }
        }

        public string Title
        {
            get {
                return question.Title;
            }
            set {
                question.Title = value;
                UpdateTitleError();
            }
        }

        public string Content
        {
            get { return question.Content; }
            set
            {
                question.Content = value;
                UpdateContentError();
            }
        }

        public List<Tag> Tags
        {
            get { return question.Tags; }
        }

        public IEnumerable<string> AllTags
        {
            get
            {
                if (allTags == null)
                {
                    using (var serviceClient = ServicesFactory.CreateClientOverflowServiceClient())
                    {
                        allTags = serviceClient.GetAllTags().Select(tag => tag.Name).ToArray();
                    }
                }

                return allTags;
            }
        }

        public ICommand Save { get; private set; }
    }
}